Explore estratégias avançadas para integrar Propriedades Personalizadas CSS (variáveis) em Web Components. Aprenda a construir sistemas de design flexíveis, sustentáveis e globalmente acessíveis.
Dominando a Estilização de Web Components: Integração Perfeita de Propriedades Personalizadas CSS para Sistemas de Design Globais
No cenário em rápida evolução do desenvolvimento web, criar interfaces de usuário reutilizáveis, sustentáveis e visualmente consistentes é primordial. Os Web Components oferecem uma maneira poderosa de encapsular a lógica e a estilização da UI, promovendo modularidade e interoperabilidade. No entanto, estilizar esses componentes de forma eficaz, especialmente em diversos projetos e equipes globais, apresenta seu próprio conjunto de desafios. É aqui que as Propriedades Personalizadas CSS, muitas vezes chamadas de Variáveis CSS, surgem como uma ferramenta indispensável. Integrá-las perfeitamente com Web Components desbloqueia um novo nível de flexibilidade e poder para construir sistemas de design sofisticados.
Este guia abrangente aprofunda a integração estratégica de Propriedades Personalizadas CSS em Web Components, oferecendo insights práticos, técnicas avançadas e exemplos do mundo real. Exploraremos como essa sinergia capacita os desenvolvedores a criar interfaces de usuário altamente tematizáveis, acessíveis e globalmente adaptáveis.
A Dupla Poderosa: Web Components e Propriedades Personalizadas CSS
Antes de mergulharmos nas estratégias de integração, vamos revisitar brevemente os pontos fortes de cada tecnologia:
Web Components: Encapsulamento e Reusabilidade
Web Components são um conjunto de APIs da plataforma web que permitem criar novas tags HTML personalizadas, reutilizáveis e encapsuladas para potencializar seus componentes web. As principais APIs incluem:
- Elementos Personalizados (Custom Elements): APIs para definir novos elementos HTML.
- Shadow DOM: APIs para anexar uma árvore DOM oculta e encapsulada a um elemento. Isso impede que estilos e marcação vazem para dentro ou para fora.
- Templates HTML: Os elementos
<template>e<slot>para conter marcação que não é renderizada imediatamente, mas pode ser clonada e usada posteriormente.
O encapsulamento fornecido pelo Shadow DOM é uma faca de dois gumes para a estilização. Embora garanta que os estilos do componente não interfiram com o resto da página, também torna desafiador estilizar componentes de fora. É precisamente aqui que as Propriedades Personalizadas CSS brilham.
Propriedades Personalizadas CSS: Estilização Dinâmica e Tematização
As Propriedades Personalizadas CSS permitem definir propriedades personalizadas (variáveis) dentro de regras CSS. Elas são definidas usando um prefixo -- (ex: --primary-color) e podem ser acessadas usando a função var() (ex: color: var(--primary-color);).
Os principais benefícios incluem:
- Valores Dinâmicos: As propriedades personalizadas podem ser atualizadas dinamicamente com JavaScript.
- Tematização: São ideais para criar componentes e aplicações tematizáveis.
- Legibilidade e Manutenibilidade: Centralizar tokens de design (como cores, fontes, espaçamento) em variáveis torna o código mais limpo e fácil de gerenciar.
- Cascata: Como as propriedades CSS padrão, as propriedades personalizadas respeitam a cascata e podem ser sobrescritas em diferentes níveis de especificidade.
Preenchendo a Lacuna: Estilizando Web Components com Propriedades Personalizadas
O desafio ao estilizar Web Components, particularmente aqueles que usam Shadow DOM, é que os estilos definidos dentro do Shadow DOM do componente são isolados. Os estilos da cascata CSS principal do documento geralmente não penetram na fronteira do Shadow DOM.
As Propriedades Personalizadas CSS oferecem uma solução poderosa porque podem ser definidas fora do Shadow DOM e depois consumidas dentro dele. Isso permite uma separação limpa de responsabilidades e um mecanismo de tematização flexível.
Estratégia 1: Expondo Propriedades Personalizadas a Partir do Componente
A abordagem mais direta e recomendada é projetar seu Web Component para expor certos aspectos de estilização como Propriedades Personalizadas CSS. Isso significa que, dentro dos estilos internos do seu componente, você usa var() para referenciar propriedades que devem ser definidas pelo consumidor do componente.
Exemplo: Um Componente de Botão Tematizável
Vamos criar um Web Component simples <themed-button>. Permitiremos que os usuários personalizem sua cor de fundo, cor do texto e raio da borda.
// themed-button.js
const template = document.createElement('template');
template.innerHTML = `
<style>
button {
/* Valores padrão se não fornecidos pelo consumidor */
--button-bg-color: #007bff;
--button-text-color: white;
--button-border-radius: 4px;
background-color: var(--button-bg-color);
color: var(--button-text-color);
border: none;
padding: 10px 20px;
border-radius: var(--button-border-radius);
cursor: pointer;
font-size: 16px;
transition: background-color 0.3s ease;
}
button:hover {
filter: brightness(90%);
}
</style>
<button><slot></slot></button>
`;
class ThemedButton extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
this.shadowRoot.appendChild(template.content.cloneNode(true));
}
}
customElements.define('themed-button', ThemedButton);
Agora, para usar e estilizar este componente de fora:
/* styles.css */
/* Estilização padrão */
body {
font-family: sans-serif;
}
/* Aplicando estilos personalizados ao componente */
.primary-button {
--button-bg-color: #28a745; /* Verde */
--button-text-color: white;
--button-border-radius: 8px;
}
.secondary-button {
--button-bg-color: #6c757d; /* Cinza */
--button-text-color: white;
--button-border-radius: 20px;
}
.danger-button {
--button-bg-color: #dc3545; /* Vermelho */
--button-text-color: white;
--button-border-radius: 0;
}
/* Definindo um tema global para todos os botões */
:root {
--global-button-bg: #007bff;
--global-button-text: #333;
}
themed-button {
--button-bg-color: var(--global-button-bg);
--button-text-color: var(--global-button-text);
}
E no seu HTML:
<body>
<themed-button class="primary-button">Ação Primária</themed-button>
<themed-button class="secondary-button">Ação Secundária</themed-button>
<themed-button class="danger-button">Excluir Item</themed-button>
<themed-button>Botão Padrão</themed-button>
</body>
Explicação:
- O componente
<themed-button>define seus estilos internos usandovar(--button-bg-color), etc. - Nós fornecemos valores padrão dentro da tag
<style>do componente. Eles atuam como fallbacks. - Podemos então visar o elemento
<themed-button>(ou um contêiner pai) em nosso CSS global e definir essas propriedades personalizadas. Os valores definidos no próprio elemento ou em seus ancestrais serão herdados e usados pelos estilos internos do componente. - O seletor
:rootnos permite definir variáveis de tema globais que podem ser consumidas por múltiplos componentes.
Estratégia 2: Usando Variáveis CSS para Tematizar Tokens de Design Globais
Para aplicações em larga escala ou sistemas de design, é comum definir um conjunto de tokens de design globais (cores, tipografia, espaçamento, etc.) e torná-los disponíveis em toda a aplicação. As Propriedades Personalizadas CSS são perfeitas para isso.
Você pode definir esses tokens globais dentro da pseudo-classe :root em sua folha de estilo principal.
/* design-tokens.css */
:root {
/* Cores */
--color-primary: #007bff;
--color-secondary: #6c757d;
--color-success: #28a745;
--color-danger: #dc3545;
--color-warning: #ffc107;
--color-info: #17a2b8;
--color-light: #f8f9fa;
--color-dark: #343a40;
--color-white: #ffffff;
--color-black: #000000;
--color-text-base: #212529;
--color-text-muted: #6c757d;
/* Tipografia */
--font-family-base: "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
--font-size-base: 16px;
--line-height-base: 1.5;
/* Espaçamento */
--spacing-unit: 8px;
--spacing-xs: calc(var(--spacing-unit) * 0.5); /* 4px */
--spacing-sm: var(--spacing-unit); /* 8px */
--spacing-md: calc(var(--spacing-unit) * 2); /* 16px */
--spacing-lg: calc(var(--spacing-unit) * 3); /* 24px */
--spacing-xl: calc(var(--spacing-unit) * 4); /* 32px */
/* Bordas */
--border-radius-sm: 4px;
--border-radius-md: 8px;
--border-radius-lg: 20px;
/* Sombras */
--box-shadow-sm: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);
}
/* Exemplo de Tema Escuro */
body.dark-theme {
--color-primary: #0d6efd;
--color-secondary: #6c757d;
--color-light: #343a40;
--color-dark: #f8f9fa;
--color-text-base: #f8f9fa;
--color-text-muted: #adb5bd;
--box-shadow-sm: 0 0.125rem 0.25rem rgba(255, 255, 255, 0.075);
}
Qualquer Web Component que adira a esses tokens de design pode então consumi-los.
// styled-card.js
const template = document.createElement('template');
template.innerHTML = `
<style>
:host {
display: block;
border: 1px solid var(--color-light);
border-radius: var(--border-radius-md);
padding: var(--spacing-lg);
background-color: var(--color-white);
box-shadow: var(--box-shadow-sm);
color: var(--color-text-base);
font-family: var(--font-family-base);
font-size: var(--font-size-base);
}
h3 {
margin-top: 0;
color: var(--color-primary);
}
</style>
<div>
<h3><slot name="title">Título Padrão</slot></h3>
<p><slot>Conteúdo padrão para o card.</slot></p>
</div>
`;
class StyledCard extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
this.shadowRoot.appendChild(template.content.cloneNode(true));
}
}
customElements.define('styled-card', StyledCard);
No seu HTML:
<body>
<!-- Usando tema padrão -->
<styled-card>
<span slot="title">Card Um</span>
Este é o conteúdo do primeiro card. Ele usa tokens de design globais.
</styled-card>
<!-- Mudando para o tema escuro -->
<body class="dark-theme">
<styled-card>
<span slot="title">Card Escuro</span>
Este card agora aparece com estilos de tema escuro.
</styled-card>
</body>
</body>
Esta estratégia é crucial para manter a consistência visual em toda uma aplicação e permite uma fácil tematização (como o modo escuro) simplesmente alterando os valores das propriedades personalizadas globais.
Estratégia 3: Estilização Dinâmica com JavaScript
As Propriedades Personalizadas CSS podem ser manipuladas com JavaScript, oferecendo controle dinâmico sobre a aparência do componente. Isso é útil para elementos interativos ou componentes que precisam se adaptar com base na entrada do usuário ou no estado da aplicação.
Exemplo: Uma Barra de Progresso com Cor Dinâmica
Vamos criar um <dynamic-progress-bar> que aceita um atributo progress e permite que sua cor de preenchimento seja definida através de uma propriedade personalizada CSS.
// dynamic-progress-bar.js
const template = document.createElement('template');
template.innerHTML = `
<style>
:host {
display: block;
width: 100%;
height: 20px;
background-color: var(--progress-bg, #e9ecef);
border-radius: var(--progress-border-radius, 4px);
overflow: hidden;
position: relative;
}
.progress-bar-fill {
height: 100%;
background-color: var(--progress-fill-color, #007bff);
width: var(--progress-width, 0%);
transition: width 0.3s ease-in-out;
}
</style>
<div class="progress-bar-fill"></div>
`;
class DynamicProgressBar extends HTMLElement {
static get observedAttributes() {
return ['progress'];
}
constructor() {
super();
this.attachShadow({ mode: 'open' });
this.shadowRoot.appendChild(template.content.cloneNode(true));
this._progressBarFill = this.shadowRoot.querySelector('.progress-bar-fill');
}
attributeChangedCallback(name, oldValue, newValue) {
if (name === 'progress') {
this.updateProgress(newValue);
}
}
connectedCallback() {
// Garante a atualização inicial se o atributo 'progress' for definido inicialmente
if (this.hasAttribute('progress')) {
this.updateProgress(this.getAttribute('progress'));
}
}
updateProgress(progressValue) {
const percentage = Math.max(0, Math.min(100, parseFloat(progressValue)));
// Usa uma propriedade personalizada CSS para a largura para aproveitar a transição CSS
this._progressBarFill.style.setProperty('--progress-width', `${percentage}%`);
}
// Método para alterar dinamicamente a cor de preenchimento
setFillColor(color) {
this.style.setProperty('--progress-fill-color', color);
}
}
customElements.define('dynamic-progress-bar', DynamicProgressBar);
Usando o componente:
// app.js
document.addEventListener('DOMContentLoaded', () => {
const progressBar = document.querySelector('dynamic-progress-bar');
// Define o progresso via atributo
progressBar.setAttribute('progress', '75');
// Define a cor de preenchimento dinamicamente usando uma propriedade personalizada
progressBar.setFillColor('#ffc107'); // Preenchimento amarelo
// Exemplo de alteração de progresso e cor com base em um evento
setTimeout(() => {
progressBar.setAttribute('progress', '30');
progressBar.setFillColor('#28a745'); // Preenchimento verde
}, 3000);
});
E no seu HTML:
<body>
<h2>Barra de Progresso Dinâmica</h2>
<dynamic-progress-bar></dynamic-progress-bar>
</body>
Pontos Chave:
- Os estilos internos do componente referenciam
var(--progress-width). - O método
updateProgressdefine o valor desta propriedade personalizada no estilo inline do elemento, acionando a transição CSS definida no shadow DOM do componente. - O método
setFillColormanipula diretamente uma propriedade personalizada definida no escopo do componente, demonstrando a capacidade do JavaScript de controlar a aparência do componente.
Estratégia 4: Estilizando Shadow Parts
Embora as Propriedades Personalizadas CSS sejam excelentes para tematização e ajustes dinâmicos, às vezes você precisa perfurar a fronteira do Shadow DOM para estilizar elementos específicos dentro do componente. As CSS Shadow Parts fornecem um mecanismo para isso.
Você pode expor elementos internos específicos do seu Web Component como "parts" usando o atributo part.
// tab-component.js
const template = document.createElement('template');
template.innerHTML = `
<style>
:host {
display: block;
font-family: var(--font-family-base, sans-serif);
}
.tab-list {
display: flex;
list-style: none;
padding: 0;
margin: 0;
border-bottom: 1px solid var(--color-secondary, #ccc);
}
.tab-item {
padding: var(--spacing-md, 16px) var(--spacing-lg, 24px);
cursor: pointer;
transition: background-color 0.2s, color 0.2s;
border: 1px solid transparent;
border-bottom: none;
margin-bottom: -1px; /* Para sobrepor a borda */
}
.tab-item.active {
background-color: var(--color-white, #fff);
color: var(--color-primary, #007bff);
border-color: var(--color-secondary, #ccc);
border-bottom-color: var(--color-white, #fff);
}
.tab-content {
padding: var(--spacing-lg, 24px);
}
</style>
<div class="tab-container">
<ul class="tab-list">
<li class="tab-item active" part="tab-item" data-tab="tab1">Aba 1</li>
<li class="tab-item" part="tab-item" data-tab="tab2">Aba 2</li>
<li class="tab-item" part="tab-item" data-tab="tab3">Aba 3</li>
</ul>
<div class="tab-content">
<div id="tab1">Conteúdo para a Aba 1</div>
<div id="tab2" style="display: none;">Conteúdo para a Aba 2</div>
<div id="tab3" style="display: none;">Conteúdo para a Aba 3</div>
</div>
</div>
`;
class TabComponent extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
this.shadowRoot.appendChild(template.content.cloneNode(true));
this._tabItems = this.shadowRoot.querySelectorAll('.tab-item');
this._tabContents = this.shadowRoot.querySelectorAll('.tab-content > div');
}
connectedCallback() {
this._tabItems.forEach(item => {
item.addEventListener('click', this._handleTabClick.bind(this));
});
}
_handleTabClick(event) {
const targetTab = event.target.dataset.tab;
this._tabItems.forEach(item => {
item.classList.toggle('active', item.dataset.tab === targetTab);
});
this._tabContents.forEach(content => {
content.style.display = content.id === targetTab ? 'block' : 'none';
});
}
disconnectedCallback() {
this._tabItems.forEach(item => {
item.removeEventListener('click', this._handleTabClick.bind(this));
});
}
}
customElements.define('tab-component', TabComponent);
Estilizando de fora usando ::part():
/* styles.css */
/* Estende os tokens de design globais */
:root {
--color-primary: #6f42c1; /* Roxo para as abas */
--color-secondary: #e9ecef;
--color-white: #ffffff;
}
/* Estilizando uma parte específica do componente de abas */
tab-component::part(tab-item) {
font-weight: bold;
text-transform: uppercase;
letter-spacing: 0.5px;
}
/* Personalizando a parte da aba ativa */
tab-component::part(tab-item).active {
background-color: var(--color-primary);
color: white;
border-color: var(--color-primary);
}
Quando usar ::part() vs. Propriedades Personalizadas CSS:
- Use Propriedades Personalizadas CSS para tematização, alteração de cores, tamanhos, espaçamentos e outros aspectos configuráveis que não alteram fundamentalmente a estrutura do elemento. Este é o método preferido para manter o encapsulamento e a flexibilidade.
- Use
::part()quando precisar sobrescrever estilos estruturais específicos de elementos dentro do Shadow DOM, como bordas, margens específicas ou estilos de fonte que são intrínsecos à apresentação do elemento e não se destinam a ser tematizáveis através de variáveis.
Considerações Globais para Sistemas de Design e Web Components
Ao construir um sistema de design com Web Components e Propriedades Personalizadas CSS para uma audiência global, vários fatores são cruciais:
1. Acessibilidade (A11y)
Contraste de Cor: Garanta que as combinações de cores padrão e tematizáveis atendam aos padrões de acessibilidade (WCAG). Teste regularmente as taxas de contraste. As Propriedades Personalizadas CSS facilitam a implementação de temas de alto contraste.
Indicadores de Foco: Propriedades personalizadas podem ser usadas para estilizar os estados de foco para elementos interativos, garantindo que a navegabilidade por teclado seja clara e visível em diferentes temas.
Internacionalização (i18n) e Localização (l10n):
Direção do Texto: Os componentes devem, idealmente, suportar as direções de texto da Esquerda para a Direita (LTR) e da Direita para a Esquerda (RTL). As Propriedades Personalizadas CSS podem ajudar a gerenciar margens e preenchimentos direcionais (ex: margin-left vs. margin-right). Usar propriedades lógicas (ex: margin-inline-start, padding-block-end) é ainda melhor.
Tipografia: Famílias e tamanhos de fonte podem precisar de ajustes para diferentes idiomas. As Propriedades Personalizadas CSS permitem sobrescrever facilmente font-family, font-size e line-height.
2. Internacionalização de Valores
Embora as Propriedades Personalizadas CSS em si não sejam traduzidas diretamente, elas podem ser usadas para *aplicar* valores localizados. Por exemplo, se o seu sistema de design usa --spacing-unit, diferentes localidades podem ter tamanhos de fonte padrão diferentes, o que afeta indiretamente a sensação do espaçamento. Mais diretamente, você pode usar propriedades personalizadas para coisas como:
--date-format: 'MM/DD/YYYY';--currency-symbol: '$';
Estes seriam definidos via JavaScript ou arquivos CSS localizados, consumidos pelos componentes ou pela lógica da aplicação ao redor deles.
3. Considerações de Desempenho
Número de Propriedades Personalizadas: Embora poderosas, um número excessivo de propriedades personalizadas pode ter um impacto menor no desempenho. No entanto, isso é geralmente insignificante em comparação com os benefícios da manutenibilidade.
Manipulação com JavaScript: Atualizações frequentes e complexas de propriedades personalizadas com JavaScript podem impactar o desempenho. Otimize agrupando atualizações ou usando transições CSS sempre que possível.
Valores de Fallback: Sempre forneça valores de fallback sensatos dentro do CSS interno do seu componente. Isso garante que o componente permaneça funcional e visualmente coerente, mesmo que o consumidor não defina as propriedades personalizadas.
4. Convenções de Nomenclatura
Adote uma convenção de nomenclatura clara e consistente para suas Propriedades Personalizadas CSS. Isso é vital para uma equipe global, onde a clareza é primordial.
- Use Prefixos: Agrupe propriedades logicamente (ex:
--color-primary,--font-size-base,--spacing-md). - Seja Descritivo: Os nomes devem indicar claramente seu propósito.
- Evite Conflitos: Esteja ciente de possíveis conflitos com especificações CSS ou outras bibliotecas.
5. Interoperabilidade com Frameworks
Web Components são agnósticos a frameworks. Ao integrá-los em frameworks como React, Angular ou Vue, passar Propriedades Personalizadas CSS é geralmente simples:
- React: Use estilos inline ou soluções de CSS-in-JS que podem visar o elemento personalizado e definir suas propriedades.
- Vue: Use estilos inline ou módulos CSS.
- Angular: Use estilos de componente ou bindings de atributos.
A chave é que as propriedades personalizadas são aplicadas à própria instância do elemento personalizado (ou a um de seus ancestrais no light DOM), que são então herdadas para o Shadow DOM.
Padrões de Integração Avançados
1. Tematização com Atributos de Dados
Em vez de depender apenas de classes CSS, você pode usar atributos de dados para acionar mudanças de tema. Isso pode ser combinado com Propriedades Personalizadas CSS.
/* global-themes.css */
[data-theme="light"] {
--background-color: #ffffff;
--text-color: #333;
}
[data-theme="dark"] {
--background-color: #333;
--text-color: #ffffff;
}
[data-theme="high-contrast"] {
--background-color: #ffff00;
--text-color: #000000;
}
Seus Web Components então consumiriam estes:
/* dentro do estilo do componente */
:host {
background-color: var(--background-color);
color: var(--text-color);
}
Esta abordagem oferece uma maneira clara e semântica de trocar de temas.
2. Tematização Dinâmica Baseada nas Preferências do Usuário (Prefers-Color-Scheme)
Aproveite as media queries CSS como prefers-color-scheme para aplicar temas automaticamente.
/* design-tokens.css */
:root {
/* Tema padrão (claro) */
--background-color: #ffffff;
--text-color: #333;
}
@media (prefers-color-scheme: dark) {
:root {
/* Sobrescritas do tema escuro */
--background-color: #333;
--text-color: #ffffff;
}
}
/* Estilo do componente */
.my-widget {
background-color: var(--background-color);
color: var(--text-color);
}
Os Web Components dentro do Shadow DOM herdarão essas propriedades quando forem definidas no light DOM.
3. Criando Bibliotecas de Tokens de Design
Empacote suas definições de Propriedades Personalizadas CSS em bibliotecas reutilizáveis. Podem ser arquivos CSS, mixins Sass/Less que geram variáveis CSS, ou até mesmo módulos JavaScript que definem variáveis programaticamente.
Isso promove consistência e permite que diferentes equipes ou projetos importem e usem facilmente o mesmo conjunto de tokens de design.
Armadilhas Comuns e Como Evitá-las
- Dependência excessiva de
::part(): Embora útil, o uso excessivo de::part()pode erodir os benefícios de encapsulamento dos Web Components. Priorize as Propriedades Personalizadas CSS para tematização. - Falta de Fallbacks: Sempre forneça valores padrão para suas propriedades personalizadas dentro dos estilos do componente.
- Nomenclatura Inconsistente: Use uma convenção de nomenclatura robusta em todo o seu sistema de design para evitar confusão.
- Não Considerar a Acessibilidade: Garanta que as paletas de cores tematizáveis atendam aos requisitos de contraste.
- Ignorar o Suporte de Navegadores: Embora as Propriedades Personalizadas CSS tenham excelente suporte nos navegadores modernos, considere polyfills ou estratégias alternativas se o suporte a navegadores muito antigos for um requisito estrito. (Nota: Polyfills para Web Components também costumam lidar com Propriedades Personalizadas CSS.)
Conclusão
A integração de Propriedades Personalizadas CSS com Web Components é um paradigma poderoso para construir interfaces de usuário modernas, flexíveis e sustentáveis. Ao expor ganchos de estilização como propriedades personalizadas, projetar com tokens de design globais e aproveitar o JavaScript para ajustes dinâmicos, os desenvolvedores podem criar componentes altamente adaptáveis.
Para equipes globais e sistemas de design em larga escala, essa abordagem oferece consistência, tematização e facilidade de manutenção inigualáveis. Adotar essas estratégias garante que seus Web Components não sejam apenas blocos de construção reutilizáveis, mas elementos inteligentes e tematizáveis, prontos para qualquer contexto, desde uma única aplicação até uma rede distribuída de projetos globais. Dominar essa sinergia é a chave para desbloquear todo o potencial da arquitetura baseada em componentes no ecossistema de desenvolvimento web moderno.